The WebSocket handshake is the initial HTTP-based negotiation process where a client and server upgrade a standard HTTP connection to the WebSocket protocol, establishing a persistent, bidirectional communication channel.
The WebSocket handshake is the critical first step in establishing a WebSocket connection. Despite WebSocket being a completely different protocol from HTTP, it deliberately starts as an HTTP request to ensure compatibility with existing web infrastructure—firewalls, proxies, and servers all understand HTTP. The client sends an HTTP GET request with special headers indicating its desire to upgrade to WebSocket, and if the server supports it, responds with a 101 Switching Protocols status, after which the connection transitions to the WebSocket protocol on the same TCP socket.
HTTP method: Must be GET with HTTP version 1.1 or higher .
Upgrade header: Upgrade: websocket signals the protocol change request .
Connection header: Connection: Upgrade indicates this is a connection-level upgrade .
Sec-WebSocket-Key: A 16-byte random value encoded in Base64. Used to prevent caching proxies from reusing old connections .
Sec-WebSocket-Version: Usually 13 (the current protocol version) .
Sec-WebSocket-Protocol: (Optional) Lists subprotocols the client supports, like chat or mqtt .
Sec-WebSocket-Extensions: (Optional) Requests extensions like permessage-deflate for compression .
Origin header: Indicates the originating page, used for security and CORS-like checks .
The most important security mechanism in the handshake is the Sec-WebSocket-Key and Sec-WebSocket-Accept exchange. The server takes the client's key, appends a fixed GUID (258EAFA5-E914-47DA-95CA-C5AB0DC85B11), computes a SHA-1 hash, and returns it Base64-encoded. This proves to the client that the server actually understands WebSocket (not just any HTTP server) and prevents cross-protocol attacks where an attacker might trick a WebSocket client into sending data to a non-WebSocket server.
101 Switching Protocols: Success! Connection will upgrade to WebSocket .
400 Bad Request: The handshake was malformed (missing headers, wrong version) .
401 Unauthorized: Authentication required (WebSocket doesn't have its own auth, but server can reject with 401) .
403 Forbidden: Server refuses the connection (origin not allowed, etc.) .
426 Upgrade Required: Server requires upgrade to WebSocket (rare) .
5xx errors: Server-side errors during handshake .
After a successful 101 response, the TCP connection is now speaking WebSocket protocol. HTTP is no longer used—all subsequent data is sent in WebSocket frames. This is why you'll see WebSocket connections in browser DevTools listed separately from HTTP requests, with their own frame inspection panel. The handshake headers are visible in the network tab, but after that, only WebSocket frames appear.
Secure WebSocket (wss://): Handshake occurs over TLS, exactly like HTTPS. The upgrade happens after TLS negotiation .
Subprotocol negotiation: Client lists supported subprotocols; server picks one (or none) in response. Common subprotocols: MQTT, STOMP, WAMP .
Compression extensions: permessage-deflate negotiates per-message compression, reducing bandwidth for text-heavy applications .
Cookies: Regular HTTP cookies are sent during handshake and can be used for session authentication .
Authentication: Often implemented by checking cookies or adding custom headers during handshake .
Understanding the handshake is crucial for debugging WebSocket connections. Common issues include missing headers, incorrect key generation, proxy servers that don't support Upgrade, and CORS-like origin restrictions. Tools like curl with --include can inspect handshake responses, and browser DevTools show the full handshake in the Network tab's WS entries. The handshake's design—starting as HTTP and upgrading—is what makes WebSocket deployable through existing web infrastructure without requiring special firewall rules or proxy configurations.